#include <iostream>
#include <string>
#include <pthread.h>
#include <cassert>
#include <unistd.h>
#include <cstring>
#include "Tread.hpp"
#include <memory>
#include <vector>
#include "mutex.hpp"
using namespace std;

// 使用线程锁来解决上述问题
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

// 全局变量观察
__thread int g_val = 100;
// 得到线程id的地址打印
char *getid(pthread_t tid)
{
    char buffer[1024];
    snprintf(buffer, sizeof buffer, "0x%x", tid);
    return buffer;
}

void *start_routine(void *args)
{
    const char *str = static_cast<const char *>(args);
    // pthread_detach(pthread_self()); 尽量在主线程设置，不然可能主线程运行起来可能就会提前join
    while (true)
    {
        cout << "我是子线程，我正在运行：,我的id是： " << getid(pthread_self()) << "g_val: " << g_val << " &g_val " << &g_val << endl;
        sleep(1);
        ++g_val;
    }
}

// 设置全局变量，来验证当前多线程并行的时候是不安全的
//  int ticket = 10000;
//  void* buytick(void* args)
//  {
//      string str = static_cast<const char*>(args);
//      while(true)
//      {
//          //使用锁，保证其安全性
//          pthread_mutex_lock(&lock);
//          if(ticket>0)
//          {
//              usleep(1234);//这里放到usleep之后再减是为了让其在进行线程切换的时候其他的线程已经改变了ticket的值
//              cout<<"正在抢票 ... 线程为: "<<str<<" ticket: "<<ticket<<endl;
//              --ticket;
//              pthread_mutex_unlock(&lock);
//          }
//          else
//          {
//              pthread_mutex_unlock(&lock);
//              break;
//          }
//      }
//  }

class Thread_Data
{
public:
    string _name;//记录名字
    pthread_mutex_t* _mutex;//锁
};

// 使用自己封装的锁来解决上述问题
int ticket = 10000;

void *buytick(void *args)
{
    string str = static_cast<const char *>(args);
    //Thread_Data* td = static_cast<Thread_Data*>(args);
    while (true)
    {
        // 使用锁，保证其安全性，这里因为我们封装过，所以只需要加个{}保证其作用域即可
        lockGuard lg(&lock);
        {
            if (ticket > 0)
            {
                usleep(1234); // 这里放到usleep之后再减是为了让其在进行线程切换的时候其他的线程已经改变了ticket的值
                //cout << "正在抢票 ... 线程为: " << td->_name << " ticket: " << ticket << endl;
                cout << "正在抢票 ... 线程为: " << str << " ticket: " << ticket << endl;

                --ticket;
            }
            else
            {
                break;
            }
        }
        // 抢完票之后可能还会做一些其他的事情
        usleep(1000);
    }
}

int main()
{
    pthread_t tid1,tid2,tid3,tid4;
    pthread_create(&tid1,nullptr,buytick,(void*)"thread 1");
    pthread_create(&tid2,nullptr,buytick,(void*)"thread 2");
    pthread_create(&tid3,nullptr,buytick,(void*)"thread 3");
    pthread_create(&tid4,nullptr,buytick,(void*)"thread 4");

    pthread_join(tid1,nullptr);
    pthread_join(tid2,nullptr);
    pthread_join(tid3,nullptr);
    pthread_join(tid4,nullptr);

    // //创建多个线程进行并发抢票
    // #define N 4
    // pthread_mutex_t lock;
    // pthread_mutex_init(&lock,nullptr);
    // vector<pthread_t> tids(N);
    // for(int i = 0;i<N;++i)
    // {
    //     //写入名字
    //     char buffer[128];
    //     snprintf(buffer,sizeof buffer,"thread: %d",i+1);
    //     Thread_Data* td = new Thread_Data();
    //     td->_name = buffer;
    //     //创建该线程
    //     pthread_create(&tids[i],nullptr,buytick,(void*)td);
    // }


    // //线程等待
    // for(auto& e:tids)
    // {
    //     pthread_join(e,nullptr);
    // }


    // // 这里使用智能指针
    // unique_ptr<Thread> thread1(new Thread(buytick, (void *)"user1", 1));
    // unique_ptr<Thread> thread2(new Thread(buytick, (void *)"user2", 2));
    // unique_ptr<Thread> thread3(new Thread(buytick, (void *)"user3", 3));
    // unique_ptr<Thread> thread4(new Thread(buytick, (void *)"user4", 4));

    // thread1->join();
    // thread2->join();
    // thread3->join();
    // thread4->join();

    // pthread_t tid;
    // int n = pthread_create(&tid,nullptr,start_routine,(void*)"thread one");
    // assert(0 == n);
    // sleep(2);
    // pthread_detach(tid);
    // //主线程
    // while(true)
    // {
    //     cout<<"我是主线程 ，我正在执行 ,id: "<< getid(pthread_self())<<"g_val: "<<g_val<<" &g_val "<<&g_val<<endl;
    //     sleep(1);
    // }

    // // int n = pthread_join(tid,nullptr);
    // // cout << "result: " << n << " : " <<strerror(n) << std::endl;
    return 0;
}